home *** CD-ROM | disk | FTP | other *** search
/ Experimental BBS Explossion 3 / Experimental BBS Explossion III.iso / gus / vts139b.zip / MODCOMMA.PAS < prev    next >
Pascal/Delphi Source File  |  1993-11-24  |  25KB  |  960 lines

  1. {****************************************************************************}
  2. {                                                                            }
  3. { MODULE:         ModCommands                                                }
  4. {                                                                            }
  5. { DESCRIPTION:    This UNIT implements the routines that interpret the       }
  6. {                 various commands that appear in a MOD file`s partiture     }
  7. {                                                                            }
  8. {                 It's independent of the number of channels used.           }
  9. {                                                                            }
  10. {                 Designed for use from within the PlayMod UNIT.             }
  11. {                                                                            }
  12. { AUTHOR:         Juan Carlos Arévalo                                        }
  13. {                                                                            }
  14. { MODIFICATIONS:  Nobody (yet... ;-)                                         }
  15. {                                                                            }
  16. { HISTORY:        02-Jan-1993 Creation/definition. It used to be part of the }
  17. {                             PlayMod UNIT, but it was getting too big.      }
  18. {                                                                            }
  19. { (C) 1992 VangeliSTeam                                                      }
  20. {____________________________________________________________________________}
  21.  
  22. UNIT ModCommands;
  23.  
  24. INTERFACE
  25.  
  26. USES SongUnit, SongElements;
  27.  
  28.  
  29.  
  30.  
  31. { Configuration. }
  32.  
  33. CONST
  34.   MyLoopMod          : BOOLEAN       = FALSE;  { If TRUE, then the MOD will loop if it was so defined.  }
  35.   PermitFilterChange : BOOLEAN       = FALSE;  { TRUE if the partiture is allowed to change the filter. }
  36.   BPMDivider         : WORD          = 125;
  37.   BPMIncrement       : WORD          = 125;
  38.   BPMCount           : WORD          = 0;
  39.   MyFirstPattern     : WORD          = 0;
  40.   MyRepStart         : WORD          = 0;
  41.   MySongLen          : WORD          = 0;
  42.   FirstPattern       : WORD          = 0;
  43.   RepStart           : WORD          = 0;
  44.   SongLen            : WORD          = 0;
  45.  
  46.  
  47.  
  48.  
  49. { Values common to all the channels. }
  50.  
  51. CONST
  52.   FilterIsOn         : BOOLEAN       = FALSE;  { Position of the filter (FALSE = OFF).                  }
  53.   Tempo              : BYTE          = 6;      { Number of ticks in the current note.                   }
  54.  
  55.  
  56.  
  57.  
  58. { Values set from outside this UNIT, apart from this one. }
  59.  
  60. CONST
  61.   NextNote           : WORD          = 1;      { Next note in the pattern.                              }
  62.   NextSeq            : WORD          = 1;      { Next pattern index (for the next note).                }
  63.                                                { They both must have been set BEFORE calling this UNIT. }
  64.  
  65.   TempoCt            : BYTE          = 0;      { Number of the actual tick. Not changed in this UNIT.   }
  66.  
  67.  
  68.  
  69.  
  70. { General definition of the state of a channel. }
  71.  
  72. TYPE                       { Channel state definition. }
  73.   PCanal = ^TCanal;
  74.   TCanal = RECORD
  75.     Note       : TFullNote;      { Note being played in the channel.   }
  76.     Instrument : PInstrumentRec; { Pointer to the instrument data.     }
  77.     Volume     : BYTE;           { Actual volume (0 - 64).             }
  78.     Period     : WORD;           { Actual Period.                      }
  79.     RealPeriod : WORD;           { Actual adjusted Period.             }
  80.  
  81.     PeriodIncr,                  { Note portamento increment.          }
  82.     PeriodDest : INTEGER;        { Note portamento destination.        }
  83.  
  84.     arpct      : BYTE;           { Arpeggio count.                     }
  85.     arp0,                        { Arpeggio 1st Period.                }
  86.     arp1,                        { Arpeggio 2nd Period.                }
  87.     arp2       : WORD;           { Arpeggio 3rd Period.                }
  88.  
  89.     VibWave,                     { Vibrato wave form.                  }
  90.     VibPos,                      { Vibrato position.                   }
  91.     VibWidth,                    { Vibrato width (period).             }
  92.     VibDepth   : BYTE;           { Vibrato depth (amplitude).          }
  93.     VibReset   : BOOLEAN;        { Vibrato reset.                      }
  94.  
  95.     TPortaIncr : INTEGER;        { Tone portamento increment.          }
  96.     VolumeIncr : SHORTINT;       { Volume increment.                   }
  97.     TPortIsFine: BOOLEAN;
  98.     VSldIsFine : BOOLEAN;
  99.  
  100.     RetrigCt   : BYTE;
  101.     RetrigVal  : BYTE;
  102.     DoRetrig   : BOOLEAN;
  103.  
  104.     SOffs      : BOOLEAN;
  105.     SOffsVal   : WORD;
  106.  
  107.     S3mRetAdd  : BOOLEAN;
  108.     S3mRetVal  : SHORTINT;
  109.   END;
  110.  
  111.  
  112.  
  113.  
  114. PROCEDURE DoTickCommand; 
  115. PROCEDURE CommandStart  (VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  116.  
  117.  
  118.  
  119.  
  120. IMPLEMENTATION
  121.  
  122. USES SongUtils, SoundDevices;
  123.  
  124.  
  125.  
  126. {----------------------------------------------------------------------------}
  127. { Rutinas de comandos, para el comienzo y cada Tick.                         }
  128. {                                                                            }
  129. { En las del tick, se entra con SI apuntando al TCanal correspondiente.      }
  130. {____________________________________________________________________________}
  131.  
  132.  
  133. { 0 xx }
  134.  
  135. PROCEDURE StartArpeggio(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  136.   CONST
  137.     ArpTable : ARRAY[0..15] OF WORD = ( $4000,$43CE,$47D6,$4C1B,
  138.                                         $50A2,$556D,$5A82,$5FE4,
  139.                                         $6597,$6BA2,$7209,$78D0,
  140.                                         $8000,$879B,$8FAD,$9837 );
  141.   VAR
  142.     f, g: LONGINT;
  143.   BEGIN
  144.     can.arpct := 0;
  145.  
  146.     f := n.Period;
  147.     IF f = 0 THEN f := can.Note.Period;
  148.  
  149.     g := f SHL 14;
  150.  
  151.     can.arp0 := f;
  152.     can.arp1 := g DIV ArpTable[can.Note.Parameter SHR  4];
  153.     can.arp2 := g DIV ArpTable[can.Note.Parameter AND $F];
  154.   END;
  155.  
  156. PROCEDURE TickArpeggio;    ASSEMBLER;
  157.   ASM
  158.  
  159.         INC     TCanal([SI]).arpct
  160.         MOV     AL,TCanal([SI]).arpct
  161.         DEC     AL
  162.         JNZ     @@2
  163.          MOV    AX,TCanal([SI]).arp0
  164.          MOV    TCanal([SI]).Period,AX
  165.         JMP    @@Fin
  166. @@2:    DEC     AL
  167.         JNZ     @@3
  168.          MOV    AX,TCanal([SI]).arp1
  169.          MOV    TCanal([SI]).Period,AX
  170.         JMP    @@Fin
  171. @@3:     MOV    AX,TCanal([SI]).arp2
  172.          MOV    TCanal([SI]).Period,AX
  173.          MOV    TCanal([SI]).arpct,0
  174. @@Fin:
  175.   END;
  176.  
  177.  
  178. { 1 xx , 2 xx }
  179.  
  180. PROCEDURE StartFinePortaUp  (VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote); FORWARD;
  181.  
  182. PROCEDURE StartFinePortaDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote); FORWARD;
  183.  
  184. PROCEDURE StartTPortUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  185.   BEGIN
  186.     IF n.Parameter <> 0 THEN
  187.       BEGIN
  188.         can.TPortaIncr  := WORD(n.Parameter) SHL 2;
  189.         can.TPortIsFine := FALSE;
  190.       END
  191.     ELSE IF can.TPortIsFine THEN
  192.       BEGIN
  193.         can.Note.Command := mcFinePortaUp;
  194.         StartFinePortaUp(Song, can, n);
  195.       END;
  196.   END;
  197.  
  198. PROCEDURE StartTPortDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  199.   BEGIN
  200.     IF n.Parameter <> 0 THEN
  201.       BEGIN
  202.         can.TPortaIncr  := WORD(n.Parameter) SHL 2;
  203.         can.TPortIsFine := FALSE;
  204.       END
  205.     ELSE IF can.TPortIsFine THEN
  206.       BEGIN
  207.         can.Note.Command := mcFinePortaDn;
  208.         StartFinePortaDown(Song, can, n);
  209.       END;
  210.   END;
  211.  
  212. PROCEDURE TickTPortUp; ASSEMBLER;
  213.   ASM
  214.  
  215.         MOV     AX,TCanal([SI]).Note.Period
  216.         SUB     AX,TCanal([SI]).TPortaIncr
  217. {
  218.         JNC     @@c
  219.           XOR   AX,AX
  220.     @@c:
  221. }
  222. {
  223.         JC      @@c2
  224.         CMP     AX,$39
  225.         JA      @@c1
  226.     @@c2:MOV    AX,$39
  227.     @@c1:
  228. }
  229.         MOV     TCanal([SI]).Note.Period,AX
  230.         MOV     TCanal([SI]).Period,AX
  231.  
  232.   END;
  233.  
  234.  
  235. PROCEDURE TickTPortDown; ASSEMBLER;
  236.   ASM
  237.  
  238.         MOV     AX,TCanal([SI]).Note.Period
  239.         ADD     AX,TCanal([SI]).TPortaIncr
  240. {
  241.         CMP     AX,$6B0
  242.         JB      @@c1
  243.          MOV    AX,$6B0
  244.     @@c1:
  245. }
  246.         MOV     TCanal([SI]).Note.Period,AX
  247.         MOV     TCanal([SI]).Period,AX
  248.  
  249.   END;
  250.  
  251.  
  252. { 3 xy }
  253.  
  254. PROCEDURE StartNPortamento(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  255.   BEGIN
  256.     IF n.Period <> 0 THEN
  257.       can.PeriodDest := n.Period
  258.     ELSE IF can.PeriodDest = 0 THEN
  259.       can.PeriodDest := can.Period;
  260.  
  261.     IF n.Parameter = 0 THEN BEGIN
  262.       IF can.PeriodIncr > 0 THEN n.Parameter := BYTE(( can.PeriodIncr) SHR 2)
  263.                             ELSE n.Parameter := BYTE((-can.PeriodIncr) SHR 2);
  264.     END;
  265.  
  266.     IF INTEGER(can.PeriodDest - can.Period) >= 0 THEN
  267.       can.PeriodIncr :=  INTEGER(WORD(n.Parameter) SHL 2)
  268.     ELSE
  269.       can.PeriodIncr := -INTEGER(WORD(n.Parameter) SHL 2);
  270.  
  271.     can.Note.Period := can.Period;
  272.   END;
  273.  
  274. PROCEDURE TickNPortamento; ASSEMBLER; 
  275.   ASM
  276.  
  277.         MOV     AX,TCanal([SI]).PeriodDest
  278.         AND     AX,AX
  279.         JZ      @@Fin
  280.         MOV     AX,TCanal([SI]).PeriodIncr
  281.         AND     AX,AX
  282.         JZ      @@Fin
  283.         MOV     BX,TCanal([SI]).Note.Period
  284.         ADD     BX,AX
  285.         TEST    AH,80h
  286.         JNZ      @@neg
  287.          CMP    BX,TCanal([SI]).PeriodDest
  288.          JA     @@pneg
  289.         JMP     @@cnt
  290. @@neg:   TEST   BH,80h
  291.          JNZ    @@pneg
  292.          CMP    BX,TCanal([SI]).PeriodDest
  293.          JAE    @@cnt
  294. @@pneg:  MOV    BX,TCanal([SI]).PeriodDest
  295. @@cnt:  MOV     TCanal([SI]).Note.Period,BX
  296.         MOV     TCanal([SI]).Period,BX
  297. @@Fin:
  298.  
  299.   END;
  300.  
  301.  
  302. { 4 xy }
  303.  
  304. PROCEDURE StartVibrato(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  305.   VAR
  306.     f : WORD;
  307.   BEGIN
  308.     f := n.Parameter AND $F;
  309.     IF f <> 0 THEN
  310.       CASE can.VibWave OF
  311.         0: can.VibWidth := f;
  312.         1: can.VibWidth := f;
  313.         2: can.VibWidth := (f*255) SHR 7;
  314.       END;
  315.  
  316.     f := n.Parameter SHR  4;
  317.     IF f <> 0 THEN can.VibDepth := f SHL 2;
  318.  
  319.     IF (n.Period <> 0) AND can.VibReset THEN
  320.       can.VibPos := 0;
  321.   END;
  322.  
  323. PROCEDURE TickVibrato;     ASSEMBLER; 
  324.   CONST
  325.     VibTabla : ARRAY[0..31] OF BYTE = (   { Sinus table for the vibrato. }
  326.         0, 24, 49, 74, 97,120,141,161,
  327.       180,197,212,224,235,244,250,253,
  328.       255,253,250,244,235,224,212,197,
  329.       180,161,141,120, 97, 74, 49, 24
  330.     );
  331.   ASM
  332.  
  333.         MOV     AH,TCanal([SI]).VibWave
  334.         MOV     DH,TCanal([SI]).VibWidth
  335.         MOV     DL,TCanal([SI]).VibPos
  336.         MOV     AL,DL
  337.         AND     AH,AH
  338.         JNZ     @@nosn
  339.          SHR    AL,2
  340.          AND    AL,1Fh
  341.          MOV    BX,OFFSET VibTabla
  342.          XLAT
  343.          JMP    @@set
  344. @@nosn: DEC     AH
  345.         JNZ     @@notr
  346.          SHL    AL,1
  347.          JNC    @@set
  348.           NOT   AL
  349. @@set:   MUL    DH
  350.          SHL    AX,1
  351.          MOV    AL,AH
  352.          XOR    AH,AH
  353.         JMP     @@calc
  354. @@notr:  MOV    AL,DH
  355.          XOR    AH,AH
  356. @@calc: MOV     BX,TCanal([SI]).Note.Period
  357.         SHL     AX,2
  358.         TEST    DL,80h
  359.         JZ      @@mas
  360.          NEG    AX
  361. @@mas:  ADD     BX,AX
  362.         MOV     TCanal([SI]).Period,BX
  363.         ADD     DL,TCanal([SI]).VibDepth
  364.         MOV     TCanal([SI]).VibPos,DL
  365.  
  366.   END;
  367.  
  368.  
  369. { 5 xy }
  370.  
  371. PROCEDURE TickVolSlide; FORWARD;
  372.  
  373. PROCEDURE TickT_VSlide; ASSEMBLER;
  374.   ASM
  375.  
  376.         CALL    TickNPortamento
  377.         JMP     TickVolSlide
  378.  
  379.   END;
  380.  
  381.  
  382. { 6 xy }
  383.  
  384. PROCEDURE TickVib_VSlide; ASSEMBLER; 
  385.   ASM
  386.  
  387.         CALL    TickVibrato
  388.         JMP     TickVolSlide
  389.  
  390.   END;
  391.  
  392.  
  393. { 7 xy }
  394.  
  395. PROCEDURE TickTremolo;     ASSEMBLER; 
  396.   ASM
  397.   END;
  398.  
  399.  
  400. { 8 xx }
  401.  
  402. PROCEDURE TickNPI1;        ASSEMBLER; 
  403.   ASM
  404.   END;
  405.  
  406.  
  407. { 9 xx }
  408.  
  409. PROCEDURE StartSampleOffs(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  410.   BEGIN
  411.     IF n.Parameter <> 0 THEN
  412.       BEGIN
  413.         can.SOffs := TRUE;
  414.         can.SOffsVal := WORD(n.Parameter) * 256;
  415.       END;
  416.   END;
  417.  
  418. PROCEDURE TickSampleOffs;  ASSEMBLER;
  419.   ASM
  420.   END;
  421.  
  422.  
  423. { A xy }
  424.  
  425. PROCEDURE StartVolSlide(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  426.   BEGIN
  427.     IF n.Parameter <> 0 THEN
  428.       BEGIN
  429.         can.VSldIsFine := FALSE;
  430.         IF n.Parameter > $F THEN can.VolumeIncr := n.Parameter SHR 4
  431.                             ELSE can.VolumeIncr := -SHORTINT(n.Parameter AND $F);
  432.       END
  433.     ELSE
  434.       BEGIN
  435.         IF can.VSldIsFine THEN
  436.           BEGIN
  437.             can.VSldIsFine := FALSE;
  438.             ASM
  439.                 MOV     SI,WORD PTR can
  440.                 CALL    TickVolSlide
  441.             END;
  442.             can.VSldIsFine := TRUE;
  443.           END;
  444.       END;
  445.  
  446.   END;
  447.  
  448. PROCEDURE TickVolSlide; ASSEMBLER;
  449.   ASM
  450.  
  451.         MOV     AL,TCanal([SI]).VSldIsFine
  452.         AND     AL,AL
  453.         JNZ     @@Sale
  454.  
  455.         MOV     AL,TCanal([SI]).Volume
  456.         MOV     AH,TCanal([SI]).VolumeIncr
  457.         ADD     AL,AH
  458.         CMP     AL,64
  459.         JBE     @@Fin
  460.          XOR    AL,AL
  461.          TEST   AH,80h
  462.          JNZ    @@Fin
  463.           MOV   AL,64
  464. @@Fin:  MOV     TCanal([SI]).Volume,AL
  465. @@Sale:
  466.   END;
  467.  
  468.  
  469.  
  470. { B xx }
  471.  
  472. PROCEDURE StartJumpPattern(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  473.   BEGIN
  474.     NextSeq := n.Parameter;
  475.     IF NextSeq > MySongLen THEN
  476.       NextNote := $FFFF
  477.     ELSE
  478.       NextNote := 1;
  479.   END;
  480.  
  481.  
  482. { C xx }
  483.  
  484. PROCEDURE StartSetVolume(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  485.   BEGIN
  486.     IF n.Parameter > 64 THEN n.Parameter := 64;
  487.     can.Volume := n.Parameter;
  488.   END;
  489.  
  490.  
  491. { D xx }
  492.  
  493. PROCEDURE StartEndPattern(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  494.   BEGIN
  495.     IF NextNote <> 1 THEN INC(NextSeq);
  496.     IF NextSeq > MySongLen THEN
  497.       NextNote := $FFFF
  498.     ELSE BEGIN
  499.       NextNote := (n.Parameter AND $0F) +
  500.                   (n.Parameter SHR   4)*10 + 1;
  501.     END;
  502.     IF NextNote <> $FFFF THEN NextNote := 1;
  503.   END;
  504.  
  505.  
  506. { F xx }
  507.  
  508. PROCEDURE StartSetTempo(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  509.   BEGIN
  510.     IF n.Parameter  > $30 THEN
  511.       BPMIncrement := n.Parameter
  512.     ELSE
  513.       IF n.Parameter <>  0  THEN Tempo := n.Parameter;
  514.   END;
  515.  
  516.  
  517. { E 0x }
  518.  
  519. PROCEDURE StartSetFilter(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  520.   BEGIN
  521.     IF PermitFilterChange THEN
  522.       FilterIsOn := n.Parameter <> 0;
  523.   END;
  524.  
  525. PROCEDURE TickSetFilter;   ASSEMBLER; 
  526.   ASM
  527.   END;
  528.  
  529.  
  530. { E 1x , E 2x }
  531.  
  532. PROCEDURE StartFinePortaUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  533.   BEGIN
  534.     IF n.Parameter <> 0 THEN
  535.       BEGIN
  536.         can.TPortaIncr  := WORD(n.Parameter) SHL 2;
  537.         can.TPortIsFine := TRUE;
  538.       END
  539.     ELSE IF NOT can.TPortIsFine THEN
  540.       BEGIN
  541.         can.Note.Command := mcTPortUp;
  542.       END;
  543.  
  544.     IF can.TPortIsFine THEN
  545.       ASM
  546.         MOV       SI,WORD PTR [can]
  547.         CALL      TickTPortUp
  548.       END;
  549.   END;
  550.  
  551. PROCEDURE StartFinePortaDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  552.   BEGIN
  553.     IF n.Parameter <> 0 THEN
  554.       BEGIN
  555.         can.TPortaIncr  := WORD(n.Parameter) SHL 2;
  556.         can.TPortIsFine := TRUE;
  557.       END
  558.     ELSE IF NOT can.TPortIsFine THEN
  559.       BEGIN
  560.         can.Note.Command := mcTPortDown;
  561.       END;
  562.  
  563.     IF can.TPortIsFine THEN
  564.       ASM
  565.         MOV       SI,WORD PTR [can]
  566.         CALL      TickTPortDown
  567.       END;
  568.   END;
  569.  
  570. PROCEDURE TickFPortUpDown; ASSEMBLER;
  571.   ASM
  572.   END;
  573.  
  574.  
  575. { E 3x }
  576.  
  577. PROCEDURE TickGlissCtrl;   ASSEMBLER; 
  578.   ASM
  579.   END;
  580.  
  581.  
  582. { E 4x }
  583.  
  584. PROCEDURE TickVibCtrl;     ASSEMBLER; 
  585.   ASM
  586.   END;
  587.  
  588.  
  589. { E 5x }
  590.  
  591. PROCEDURE TickFineTune;    ASSEMBLER; 
  592.   ASM
  593.   END;
  594.  
  595.  
  596. { E 6x }
  597.  
  598. PROCEDURE TickJumpLoop;    ASSEMBLER; 
  599.   ASM
  600.   END;
  601.  
  602.  
  603. { E 7x }
  604.  
  605. PROCEDURE TickTremCtrl;    ASSEMBLER; 
  606.   ASM
  607.   END;
  608.  
  609.  
  610. { E 8x }
  611.  
  612. PROCEDURE TickNPI2;        ASSEMBLER; 
  613.   ASM
  614.   END;
  615.  
  616.  
  617. { E 9x }
  618.  
  619. PROCEDURE StartRetrigNote(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  620.   BEGIN
  621.     IF n.Parameter <> 0 THEN
  622.       can.retrigval := n.Parameter;
  623.   END;
  624.  
  625. PROCEDURE TickRetrigNote;  ASSEMBLER; 
  626.   ASM
  627.         INC     TCanal([SI]).retrigct
  628.         MOV     AL,TCanal([SI]).retrigct
  629.         CMP     AL,TCanal([SI]).retrigval
  630.         JC      @@ret
  631.          MOV    TCanal([SI]).retrigct,0
  632.          MOV    TCanal([SI]).doretrig,1
  633. @@ret:
  634.   END;
  635.  
  636.  
  637. { E Ax y E Bx }
  638.  
  639. PROCEDURE StartVolFineUp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  640.   BEGIN
  641.     IF n.Parameter <> 0 THEN
  642.       BEGIN
  643.         can.VSldIsFine := TRUE;
  644.         can.VolumeIncr := n.Parameter AND $F;
  645.       END;
  646.  
  647.     IF can.VSldIsFine THEN
  648.       BEGIN
  649.         can.VSldIsFine := FALSE;
  650.           ASM
  651.                 MOV     SI,WORD PTR can
  652.                 CALL    TickVolSlide
  653.           END;
  654.         can.VSldIsFine := TRUE;
  655.       END;
  656.   END;
  657.  
  658. PROCEDURE StartVolFineDown(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  659.   BEGIN
  660.     IF n.Parameter <> 0 THEN
  661.       BEGIN
  662.         can.VSldIsFine := TRUE;
  663.         can.VolumeIncr := -SHORTINT(n.Parameter AND $F);
  664.       END;
  665.  
  666.     IF can.VSldIsFine THEN
  667.       BEGIN
  668.         can.VSldIsFine := FALSE;
  669.           ASM
  670.                 MOV     SI,WORD PTR can
  671.                 CALL    TickVolSlide
  672.           END;
  673.         can.VSldIsFine := TRUE;
  674.       END;
  675.   END;
  676.  
  677. PROCEDURE TickVolFineUpDn; ASSEMBLER; 
  678.   ASM
  679.                 JMP     TickVolSlide
  680.   END;
  681.  
  682.  
  683. { E Cx }
  684.  
  685. PROCEDURE TickNoteCut;     ASSEMBLER; 
  686.   ASM
  687.   END;
  688.  
  689.  
  690. { E Dx }
  691.  
  692. PROCEDURE TickNoteDelay;   ASSEMBLER; 
  693.   ASM
  694.   END;
  695.  
  696.  
  697. { E Ex }
  698.  
  699. PROCEDURE TickPattDelay;   ASSEMBLER; 
  700.   ASM
  701.   END;
  702.  
  703.  
  704. { E Fx }
  705.  
  706. PROCEDURE TickFunkIt;      ASSEMBLER; 
  707.   ASM
  708.   END;
  709.  
  710.  
  711. { 0 00 }
  712.  
  713. PROCEDURE TickNone;        ASSEMBLER; 
  714.   ASM
  715.   END;
  716.  
  717.  
  718. PROCEDURE StartOktArp(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  719.   CONST
  720.     ArpTable : ARRAY[0..15] OF WORD = ( $4000,$43CE,$47D6,$4C1B,
  721.                                         $50A2,$556D,$5A82,$5FE4,
  722.                                         $6597,$6BA2,$7209,$78D0,
  723.                                         $8000,$879B,$8FAD,$9837 );
  724.   VAR
  725.     f, g: LONGINT;
  726.   BEGIN
  727.     can.arpct := 0;
  728.  
  729.     f := n.Period;
  730.     IF f = 0 THEN f := can.Note.Period;
  731.  
  732.     g := f SHL 14;
  733.  
  734.     can.arp0 := f;
  735.     can.arp2 := g DIV ArpTable[can.Note.Parameter AND $F];
  736.  
  737.     f := f SHL 1;
  738.     can.arp1 := g DIV ArpTable[(can.Note.Parameter SHR  4) XOR $F];
  739.   END;
  740.  
  741.  
  742.  
  743. PROCEDURE TickArpeggio2;   ASSEMBLER;
  744.   ASM
  745.  
  746.         INC     TCanal([SI]).arpct
  747.         MOV     AL,TCanal([SI]).arpct
  748.         DEC     AL
  749.         JNZ     @@2
  750.          MOV    AX,TCanal([SI]).arp1
  751.          MOV    TCanal([SI]).Period,AX
  752.         JMP    @@Fin
  753. @@2:    DEC     AL
  754.         JNZ     @@3
  755.          MOV    AX,TCanal([SI]).arp2
  756.          MOV    TCanal([SI]).Period,AX
  757.         JMP    @@Fin
  758. @@3:    DEC     AL
  759.         JNZ     @@4
  760.          MOV    AX,TCanal([SI]).arp1
  761.          MOV    TCanal([SI]).Period,AX
  762.         JMP    @@Fin
  763. @@4:     MOV    AX,TCanal([SI]).arp0
  764.          MOV    TCanal([SI]).Period,AX
  765.          MOV    TCanal([SI]).arpct,0
  766. @@Fin:
  767.   END;
  768.  
  769.  
  770.  
  771. PROCEDURE StartS3mRetrigNote(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  772.   CONST
  773.     RetMult : ARRAY[0..15] OF BYTE     = ( 0,  0,  0,  0,  0,   0, $0C, $08,
  774.                                            0,  0,  0,  0,  0,   0, $18, $20 );
  775.     RetAdd  : ARRAY[0..15] OF SHORTINT = ( 0, -1, -2, -4, -8, -16,   0,   0,
  776.                                            0,  1,  2,  4,  8,  16,   0,   0 );
  777.   BEGIN
  778.     IF n.Parameter <> 0 THEN
  779.       BEGIN
  780.         can.s3mretadd := RetMult[n.Parameter SHR 4] = 0;
  781.         IF can.s3mretadd THEN
  782.           can.s3mretval := RetAdd[n.Parameter SHR 4]
  783.         ELSE
  784.           can.s3mretval := RetMult[n.Parameter SHR 4];
  785.  
  786.         n.Parameter := n.Parameter AND $F;
  787.  
  788.         StartRetrigNote(Song, can, n);
  789.       END;
  790.   END;
  791.  
  792. PROCEDURE TickS3mRetrigNote;  ASSEMBLER;
  793.   ASM
  794.         CALL    TickRetrigNote
  795.  
  796.         CMP     TCanal([SI]).doretrig,0
  797.         JZ      @@ret
  798.         CMP     TCanal([SI]).s3mretadd,0
  799.         JNZ     @@add
  800.          MOV    AL,TCanal([SI]).s3mretval
  801.          MOV    AH,TCanal([SI]).volume
  802.          MUL    AH
  803.          CMP    AX,16
  804.          JNC    @@c1
  805.           MOV   AX,16
  806.     @@c1:SHR    AX,4
  807.          CMP    AX,63
  808.          JC     @@c2
  809.           MOV   AL,63
  810.     @@c2:MOV    TCanal([SI]).volume,AL
  811.         JMP     @@ret
  812.  
  813.     @@add:
  814.          MOV    AL,TCanal([SI]).s3mretval
  815.          MOV    AH,TCanal([SI]).volume
  816.          ADD    AH,AL
  817.          JNC    @@c3
  818.           MOV   AH,0
  819.     @@c3:CMP    AH,63
  820.          JC     @@c4
  821.           MOV   AH,63
  822.     @@c4:MOV    TCanal([SI]).volume,AH
  823.  
  824. @@ret:
  825.   END;
  826.  
  827.  
  828.  
  829.  
  830.  
  831.  
  832.  
  833. CONST
  834.   TickCommOfs : ARRAY[mcNone..mcLast] OF WORD = (
  835.     OFS(TickNone),       { 0 00 }
  836.  
  837.     OFS(TickArpeggio),   { 0 xx }
  838.     OFS(TickTPortUp),    { 1 xx }
  839.     OFS(TickTPortDown),  { 2 xx }
  840.     OFS(TickNPortamento),{ 3 xy }
  841.     OFS(TickVibrato),    { 4 xy }
  842.     OFS(TickT_VSlide),   { 5 xy }
  843.     OFS(TickVib_VSlide), { 6 xy }
  844.     OFS(TickTremolo),    { 7 xy }
  845.     OFS(TickNPI1),       { 8 xx }
  846.     OFS(TickSampleOffs), { 9 xx }
  847.     OFS(TickVolSlide),   { A xy }
  848.     OFS(TickNone),       { B xx }
  849.     OFS(TickNone),       { C xx }
  850.     OFS(TickNone),       { D xx }
  851.     OFS(TickNone),       { E xy }
  852.     OFS(TickNone),       { F xx }
  853.  
  854.     OFS(TickSetFilter),  { E 0x }
  855.     OFS(TickFPortUpDown),{ E 1x }
  856.     OFS(TickFPortUpDown),{ E 2x }
  857.     OFS(TickGlissCtrl),  { E 3x }
  858.     OFS(TickVibCtrl),    { E 4x }
  859.     OFS(TickFineTune),   { E 5x }
  860.     OFS(TickJumpLoop),   { E 6x }
  861.     OFS(TickTremCtrl),   { E 7x }
  862.     OFS(TickNPI2),       { E 8x }
  863.     OFS(TickRetrigNote), { E 9x }
  864.     OFS(TickVolFineUpDn),{ E Ax }
  865.     OFS(TickVolFineUpDn),{ E Bx }
  866.     OFS(TickNoteCut),    { E Cx }
  867.     OFS(TickNoteDelay),  { E Dx }
  868.     OFS(TickPattDelay),  { E Ex }
  869.     OFS(TickFunkIt),     { E Fx }
  870.  
  871.     OFS(TickArpeggio),   { Okt  }
  872.     OFS(TickArpeggio2),  { Okt  }
  873.  
  874.     OFS(TickS3mRetrigNote), { S3m  }
  875.  
  876.     OFS(TickNone)        { 0 00 }
  877.  
  878.   );
  879.  
  880. PROCEDURE DoTickCommand; ASSEMBLER;
  881.   ASM
  882.                 CMP     BX,mcLast*2
  883.                 JNC     @@1
  884.                 MOV     TCanal([SI]).doretrig,0
  885.                 ADD     BX,OFFSET TickCommOfs
  886.                 CALL    WORD PTR [BX]
  887. @@1:
  888.   END;
  889.  
  890.  
  891.  
  892.  
  893. PROCEDURE CommandStart(VAR Song: TSong; VAR can: TCanal; VAR n: TFullNote);
  894.   CONST
  895.     f   : INTEGER      = 0;
  896.     g   : INTEGER      = 0;
  897.   BEGIN
  898.  
  899.     IF (can.Note.Command    = mcArpeggio)  OR
  900.        (((can.Note.Command  = mcVibrato) OR
  901.          (can.Note.Command  = mcVib_VSlide)) AND
  902.         ((       n.Command <> mcVibrato) AND
  903.          (       n.Command <> mcVib_VSlide))) THEN can.Period := can.Note.Period;
  904.  
  905.     IF ((can.Note.Command <> mcS3mRetrigNote) AND
  906.         (can.Note.Command <> mcRetrigNote))   AND
  907.        ((       n.Command  = mcS3mRetrigNote) OR
  908.         (       n.Command  = mcRetrigNote))   THEN
  909.       can.retrigct := 0;
  910.  
  911.     IF (can.Note.Command =  mcNPortamento) AND
  912.        (       n.Command <> mcNPortamento) THEN
  913.       BEGIN
  914.         can.Note.Period := can.PeriodDest;
  915.         can.Period      := can.PeriodDest;
  916.       END;
  917.  
  918.     IF (n.Period <> 0) THEN
  919.       can.Note.Period := n.Period;
  920.  
  921.     can.SOffs := FALSE;
  922.  
  923.     can.Note.Command   := n.Command;
  924.     can.Note.Parameter := n.Parameter;
  925.  
  926.     CASE n.Command OF
  927.       mcArpeggio:      StartArpeggio     (Song, can, n);
  928.       mcTPortUp:       StartTPortUp      (Song, can, n);
  929.       mcTPortDown:     StartTPortDown    (Song, can, n);
  930.       mcNPortamento:   StartNPortamento  (Song, can, n);
  931.       mcVibrato:       StartVibrato      (Song, can, n);
  932.       mcJumpPattern:   StartJumpPattern  (Song, can, n);
  933.       mcT_VSlide,
  934.       mcVib_VSlide,
  935.       mcVolSlide:      StartVolSlide     (Song, can, n);
  936.       mcSampleOffs:    StartSampleOffs   (Song, can, n);
  937.       mcSetVolume:     StartSetVolume    (Song, can, n);
  938.       mcEndPattern:    StartEndPattern   (Song, can, n);
  939.       mcSetTempo:      StartSetTempo     (Song, can, n);
  940.       mcSetFilter:     StartSetFilter    (Song, can, n);
  941.       mcRetrigNote:    StartRetrigNote   (Song, can, n);
  942.       mcVolFineUp:     StartVolFineUp    (Song, can, n);
  943.       mcVolFineDown:   StartVolFineDown  (Song, can, n);
  944.       mcFinePortaUp:   StartFinePortaUp  (Song, can, n);
  945.       mcFinePortaDn:   StartFinePortaDown(Song, can, n);
  946.       mcOktArp:        StartOktArp       (Song, can, n);
  947.       mcOktArp2:       StartOktArp       (Song, can, n);
  948.       mcS3mRetrigNote: StartS3mRetrigNote(Song, can, n);
  949.     END;
  950.  
  951.     IF (n.Period <> 0) AND (n.Command <> mcNPortamento) THEN
  952.       can.Period := n.Period;
  953.  
  954.   END;
  955.  
  956.  
  957.  
  958.  
  959. END.
  960.